<template>
    <div class="tree-container">
        <template v-for="item in treeData" :key="item[fieldKey.key]">
            <div class="tree-item"
                :style="{ '--level': level }">
                <div class="tree-icon">
                    <slot name="icon-unfold">
                        <el-icon v-if="item[fieldKey.children] && unfoldList.includes(item[fieldKey.key])"
                        @click="unfold(item)" ><CaretBottom /></el-icon>
                    </slot>
                    <slot name="icon-collapse">
                        <el-icon v-if="item[fieldKey.children] && !unfoldList.includes(item[fieldKey.key])"
                        @click="unfold(item)" ><CaretRight /></el-icon>
                    </slot>
                </div>
                <div class="tree-item-title">
                    <slot :node="item">{{ item[fieldKey.title] }}</slot>
                </div>
            </div>
            <Tree v-if="item[fieldKey.children] && unfoldList.includes(item[fieldKey.key])"
                :treeData="item[fieldKey.children]" :field="field" :level="level + 1" v-model:value="key">
                <template #default="{ node }">
                    <slot :node="node"></slot>
                </template>
            </Tree>
        </template>
    </div>
</template>

<script setup>
import { computed, watch, ref,onMounted } from "vue";

const defaultField = {
    title: "title",
    children: "children",
    key: "key"
};

const props = defineProps({
    treeData: {
        type: Array,
        required: true,
        default: () => []
    },
    field: {
        type: Object,
        required: true
    },
    level: {
        type: Number,
        default: 1
    },
    value: {
        type: String,
        defeult: ""
    },
    defaultUnfold: {
        type: Array,
        default: () => []
    }
});
const autoUnfold = (tree) => {
    for (const node of tree) {
        if (node[fieldKey.value.key] === key.value) {
            return [];
        }
        if (node.children) {
            const childPath = autoUnfold(node.children);
            if (childPath) {
                unfoldList.value.push(node[fieldKey.value.key]);
                return [node, ...childPath];
            }
        }
    }
    return undefined;
};
watch(
    () => props.treeData,
    () => {
        autoUnfold(props.treeData);
    }
);
const fieldKey = computed(() => ({
    key: props.field?.key || defaultField.key,
    title: props.field?.title || defaultField.title,
    children: props.field?.children || defaultField.children
}));
const emit = defineEmits(["change", "update:value"]);

const key = computed({
    get: () => {
        return props.value;
    },
    set: val => {
        emit("update:value", val);
        emit("change", val);
    }
});
const unfoldList = ref([...props.defaultUnfold]);
const unfold = (item) => {
    const isHave = unfoldList.value.includes(item[fieldKey.value.key]);
    unfoldList.value = isHave
        ? unfoldList.value.filter(v => v != item[fieldKey.value.key])
        : [...unfoldList.value, item[fieldKey.value.key]];
};
onMounted(() => {
    autoUnfold(props.treeData);
});
</script>

<style lang="scss" scoped>
.tree-item {
    padding-left: calc(var(--level) * 16px);
    height: 40px;
    display: flex;
    align-items: center;
    cursor: pointer;
    padding-right: 16px;
    box-sizing: border-box;
    .tree-icon {
        width: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .tree-item-title {
        display: flex;
        flex: 1;
        justify-content: space-between;
        align-items: center;
        user-select: none;
        &:hover {
            color: #007dff;
        }
    }
}

.active-tree-item {
    background: #d9e8ff;
    color: #007dff;
}
</style>